#!/usr/bin/python
#  This is part of Scopia Visual Framework
#
#  Functions to render a text to a texture
#
#  Copyright (C) 2008  Scopia Visual Interfaces Systems 
#                      http://www.scopia.es
#
#  author: Alejandro Conty
#  contributors:
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.


import Image, ImageFont, ImageDraw
import math

font16 = ImageFont.truetype("scopiavf/font/sans.ttf", 16)
font32 = ImageFont.truetype("scopiavf/font/sans.ttf", 32)
font48 = ImageFont.truetype("scopiavf/font/sans.ttf", 48)

def nextPower( val ):
    "Returns the first 2 power equal or grater than val"
    p = 1
    resto = 0
    while val != 1:
        resto = (resto << 1) | (val & 1)
        val >>= 1
        p <<= 1
    if resto: p <<= 1
    return p

def render( text, width, height ):
    """Creates a PIL image with the needed dimensions to hold the text
       and renders it to the image. The returned image will be ok to
       render at width/height aspect ratio."""
    im = Image.new('RGB',(0,0) )
    draw = ImageDraw.Draw( im )
    rW, rH = draw.textsize( text, font = font48)
    area = rW * rH
    ratio = float(height) / float(width)
    imW = int(math.sqrt( area / ratio ))
    lines = splitLines( text, imW, draw, font48 )
    imH = rH * len(lines)
    imW = max( [ t[1] for t in lines ] ) + 24
    tratio = float(imH) / float(imW)
    if tratio < ratio: 
        offX, offY = 0, int( (ratio * imW  - imH)*0.5 )
        imH = int( ratio * imW )
    else:
        offX, offY = int( (imH / ratio  -imW)*0.5 ), 0
        imW = int( imH / ratio )
    offX += 12
    im = Image.new('RGBA',(imW,imH), (255, 255, 255, 255))
    draw = ImageDraw.Draw( im )
    for i in xrange(len(lines)):
        draw.text( (0 + offX, i*rH + offY), lines[i][0], font = font48, fill=(0,0,0) )
    outW, outH = nextPower(imW), nextPower(imH)
    if outW != imW or outH != imH: im = im.resize( (outW, outH), Image.BILINEAR )
    return im

def splitLines( text, width, draw, font ):
    """Splits a text among lines to avoid lines larger than 'width'. Now
       still doesn't handle newlines or any formating.

            text        Text to render
            width       Maximum line length in pixels
            draw        Drawer instance from PIL
            font        Font to use"""
    spacew, height = draw.textsize(' ', font=font48)
    words = text.split()
    lines = []
    line = ''
    w = 0
    while words:
        if line: word = ' ' + words[0]
        else: word = words[0]
        nextw, nexth = draw.textsize(word, font=font48)
        if (w + nextw) <= width or not line:
            line += word
            w += nextw
            words = words[1:]
        else:
            lines.append( (line, w) )
            line = ''
            w = 0
    if line: lines.append( (line, w) )
    return lines
